﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json;
using System;
using System.Buffers;
using System.Text;
using System.Threading.Tasks;
namespace Zeus.Mvc.Results.Implementations
{
    public class ZeusResultExecutor : IZeusResultExecutor
    {
        private static readonly string DefaultContentType = new MediaTypeHeaderValue("application/json")
        {
            Encoding = Encoding.UTF8
        }.ToString();

        private readonly IArrayPool<char> _charPool;

        public ZeusResultExecutor(
            IHttpResponseStreamWriterFactory writerFactory,
            ILogger<ZeusResultExecutor> logger,
            ArrayPool<char> charPool)
        {
            if (charPool == null)
            {
                throw new ArgumentNullException(nameof(charPool));
            }
            WriterFactory = writerFactory ?? throw new ArgumentNullException(nameof(writerFactory));
            Logger = logger ?? throw new ArgumentNullException(nameof(logger));
            _charPool = new ZeusResultArrayPool<char>(charPool);
        }

        protected ILogger Logger { get; }


        /// <summary>
        /// Gets the <see cref="IHttpResponseStreamWriterFactory"/>.
        /// </summary>
        protected IHttpResponseStreamWriterFactory WriterFactory { get; }


        public Task ExecuteAsync(ActionContext context, ZeusResult result)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (result == null)
            {
                throw new ArgumentNullException(nameof(result));
            }
            var response = context.HttpContext.Response;
            ResponseContentTypeHelper.ResolveContentTypeAndEncoding(
                result.ContentType,
                response.ContentType,
                DefaultContentType,
                out var resolvedContentType,
                out var resolvedContentTypeEncoding);
            response.ContentType = resolvedContentType;
            if (result.StatusCode != null)
            {
                response.StatusCode = result.StatusCode.Value;
            }

            //var serializerSettings = result.SerializerSettings ?? Options.SerializerSettings;
            //Logger.JsonResultExecuting(result.Value);

            using (var writer = WriterFactory.CreateWriter(response.Body, resolvedContentTypeEncoding))
            {
                using (var jsonWriter = new JsonTextWriter(writer))
                {
                    jsonWriter.ArrayPool = _charPool;
                    jsonWriter.CloseOutput = false;
                    jsonWriter.AutoCompleteOnClose = false;

                    var jsonSerializer = JsonSerializer.Create(result.JsonSerializerSettings);
                    jsonSerializer.Serialize(jsonWriter, result.Data);

                }
            }
            return Task.CompletedTask;
        }
    }
}
